#pragma once
#include <iostream>
#include <memory>
#include "Epoller.hpp"
#include "Common.hpp"
#include "Connection.hpp"
#include "Socket.hpp"
#include "Channel.hpp"

using namespace SocketModule;

// Listener专门获取新连接
// 我们通过继承Connection类来让我们的listenfd同常规的Connection一样进行管理
// 这样我们在Reactor中可以通过使用Connection指针通过多态指向这个listener对象
class Listener : public Connection
{
public:
    Listener(uint16_t port = defaultfd)
        : _port(port),
          _listensock(std::make_unique<TcpSocket>())
    {
        _listensock->BuildTcpSocketMethod(_port);
        // 设置listensocket要让epoll关心的是EPOLLIN也就是读事件
        // 由于是继承了Connection类，因此在这里可以直接使用其内部的设置要关心事件的方法
        SetEvent(EPOLLIN | EPOLLET);
        // 采用ET模式时先把fd设置为非阻塞
        SetNonBlock(_listensock->Fd());
    }

    // 获取fd的方法
    int GetSockFd() override
    {
        return _listensock->Fd();
    }

    // 读取方法
    void Recver() override
    {
        // accept
        // LOG(LogLevel::DEBUG) << "进入Listener模块的Recver函数";
        InetAddr client;
        // 新连接就绪了，我们不能保证只有一个连接到来，要一次性把所有的连接获取上来
        // while循环获取，ET模式下sockfd设置为非阻塞——listensock本身设置为非阻塞
        while (true)
        {
            int sockfd = _listensock->Accept(&client);
            if (sockfd == ACCEPT_ERR) // 出错
                break;
            else if (sockfd == ACCEPT_CONTINUE)
            {
                // 由于中断返回，因此要重新accept操作
                continue;
            }
            else if (sockfd == ACCEPT_DONE)
                // 底层没有新连接就绪
                break;
            else
            {
                // 我们获得的是一个合法的fd
                // 我们就通过基类Connection指针指向Channel普通fd类对象
                // 来构建普通fd对应的Connection对象
                std::shared_ptr<Connection> conn = std::make_shared<Channel>(sockfd, client);
                // 设置一下要让epoll关心该fd的哪个事件以及设置为ET模式
                conn->SetEvent(EPOLLIN | EPOLLET);

                // 注册一下处理Channel的方法
                if (_handler != nullptr) // 上层给listener注册了回调方法
                    conn->RegisterHandler(_handler);

                // 将该conn使用listenfd对应的Reactor对象中AddConnection方法
                // 将其建立映射
                GetOwner()->AddConnection(conn);
            }
        }
    }

    // listenfd是不需要写入方法和处理异常的，我们置空就成
    //  写入方法
    void Sender() {}
    // 处理异常的方法
    void Excepter() {}

    ~Listener() {}

private:
    uint16_t _port;
    std::unique_ptr<Socket> _listensock;
};